; UNIT XFER; {Copyright 1983, 1984 Apple Computer, Inc.}

; {changed 01/20/83 2026   Added EqualBytes
; {changed 01/05/83 2149   Moved several routines to CLASLIB so they can go into PASLIB;
;			   Here we still have (in SgCLAres):
;			        LIntDivLint, LIntDivInt, LIntMulInt, LIntAndLInt, LIntOrLInt,
;			        XferLeft, XferRight, RotatePattern, EnterLisabug}
; {changed 01/01/83 2000   Added %_JmpTo, %_ExitCaller, %_ExitFunny, %_CallMethod, %_Super;
;			   Replaced IsJsr by %_NextMethod;
;			   Deleted XPNewMethod;
;			   Changed Segment from SgABCres to SgCLAres & added some SgCLAini procedures;
;			   Added $D information conditioned on DEBUGF flag;
;			   (Note: SP=A7)}
; {changed 09/13/83 1115   RELEASE TK7D TO TOOLKIT TEAM}
; {changed 08/30/83 2000   RELEASE TK7C TO TOOLKIT TEAM}


;=============================================================================================
DEBUGF  .EQU  1		        ; 1 to include $D+ info, 0 to exclude it
;=============================================================================================

        .MACRO HEAD
          .IF DEBUGF
            LINK    A6,#0       ; These two instructions form a slow no-op
            MOVE.L  (SP)+,A6
          .ENDC
        .ENDM

        .MACRO TAIL
          .IF DEBUGF
            UNLK    A6
            RTS
            .ASCII  %1
          .ENDC
        .ENDM


;=============================================================================================
        .SEG    'SgXFER'
;=============================================================================================


        .PROC XFERLEFT
        HEAD

; PROCEDURE XferLeft(source, dest: TP; nBytes: INTEGER);
;
; uses A0,A1,D0,D1
;

        MOVE.L  (SP)+,D1        ; POP RETURN ADDRESS
        MOVE.W  (SP)+,D0        ; D0 := NBYTES
        MOVE.L  (SP)+,A1        ; A1 := DEST
        MOVE.L  (SP)+,A0        ; A0 := SOURCE
        MOVE.L  D1,-(SP)        ; PUSH RETURN ADDRESS FOR RTS

        SUB.W   #1,D0	        ; DECREMENT NBYTES

        BLT.S   RTSLEFT	        ; NBYTES <= 0, SO EXIT

XFER    MOVE.B  (A0)+,(A1)+
        DBF     D0,XFER

RTSLEFT RTS

        TAIL    'XFERLEFT'

;=============================================================================================

        .PROC XFERRIGH
        HEAD

; PROCEDURE XferRight(source, dest: TP; nBytes: INTEGER);
;
; uses A0,A1,D0,D1
;

        MOVE.L  (SP)+,D1        ; POP RETURN ADDRESS
        MOVE.W  (SP)+,D0        ; D0 := NBYTES
        MOVE.L  (SP)+,A1        ; A1 := DEST
        MOVE.L  (SP)+,A0        ; A0 := SOURCE
        MOVE.L  D1,-(SP)        ; PUSH RETURN ADDRESS FOR RTS

        TST.W   D0	        ; TEST NBYTES
        BLE.S   RTSRIGH	        ; NBYTES <= 0, SO EXIT

        ADDA.W  D0,A0	        ; START AT RIGHT END
        ADDA.W  D0,A1

        SUB.W   #1,D0	        ; DECREMENT NBYTES

XFER    MOVE.B  -(A0),-(A1)
        DBF     D0,XFER

RTSRIGH RTS

        TAIL    'XFERRIGH'

;=============================================================================================

        .PROC EqualBytes
        HEAD

; PROCEDURE EqualBytes(source, dest: TP; nBytes: INTEGER);
;
; uses A0,A1,D0,D1
;

        MOVE.L  (SP)+,D1        ; POP RETURN ADDRESS
        MOVE.W  (SP)+,D0        ; D0 := NBYTES
        MOVE.L  (SP)+,A1        ; A1 := DEST
        MOVE.L  (SP)+,A0        ; A0 := SOURCE
        MOVE.L  D1,-(SP)        ; PUSH RETURN ADDRESS FOR RTS

        MOVE.B  #1,4(SP)        ; RETURN TRUE UNLESS PROVEN UNEQUAL

        SUB.W   #1,D0	        ; DECREMENT NBYTES

        BLT.S   RTSEQUL	        ; NBYTES <= 0, SO EXIT

XFER    MOVE.B  (A0)+,D1
        CMP.B   (A1)+,D1
        BNE     UNEQUL
        DBF     D0,XFER

RTSEQUL RTS

UNEQUL  CLR.B   4(SP)	        ; RETURN FALSE
        RTS

        TAIL    'EQUALBYT'

;=============================================================================================


        .PROC ROTATEPA
        HEAD

; PROCEDURE RotatePattern(pInPat, pOutPat: ^Pattern; dh, dv: LONGINT);
;
; uses A0-A2,D0-D4
;

        MOVEM.L (SP)+,D0-D2/A0-A1  ; D0 := RETURN ADDRESS, D1 := dv; D2 := dh, A0 := pOutPat, A1 := pInPat
        MOVE.L  D0,-(SP)	   ; PUSH RETURN ADDRESS FOR RTS
        MOVEM.L A2/D3-D4,-(SP)	   ; Save A2,D3,D4

        AND.L   #7,D2		   ; dh := dh MOD 8

; ***** FOR D3 := 7 DOWNTO 0 DO *****

        MOVE.W  #7,D3	        ; Loop count

; *****	   BEGIN *****

RLOOP   MOVE.B  $00(A1,D3.W),D0 ; D0 := next byte in inPat

        ROL.B   D2,D0	        ; Rotate byte in D0 left by D2 (dh)

        MOVE.W  D3,D4
        SUB.W   D1,D4
        AND.W   #7,D4	        ; D4 := (D3 - dv) MOD 8

        MOVE.B  D0,$00(A0,D4.W) ; next byte in outPat := D0

        DBF     D3,RLOOP

; *****	   END; *****

        MOVEM.L (SP)+,A2/D3-D4  ; Restore A2,D3,D4

        RTS

        TAIL    'ROTATEPA'

;=============================================================================================

        .FUNC LINTDIVL
        HEAD

; FUNCTION  LIntDivLint(i, j: LONGINT): LONGINT;
;
; uses A0,D0,D1
;

        .REF    LD

        MOVE.L  (SP)+,A0        ; Return address

        MOVE.L  (SP)+,D0        ; D0 := j
        MOVE.L  (SP)+,D1        ; D1 := i

CHEK    CMP.L   #32767,D0       ; Is j too long to use LIntDivInt?
        BGT     TOOLONG	        ; Too big
        CMP.L   #-32768,D0
        BLT     TOOLONG	        ; Too small
        JMP     LD	        ; Can't BGT LD in this assembler

TOOLONG ASR.L   #1,D0
        ASR.L   #1,D1
        JMP     CHEK

        TAIL    'LINTDIVL'

;=============================================================================================

        .FUNC LINTDIVI
        HEAD

; FUNCTION  LIntDivInt(i: LONGINT; j: INTEGER): LONGINT;
;
; uses A0,D0,D1,D2
;

        .DEF    LD

        MOVE.L  (SP)+,A0        ; Return address

        MOVE.W  (SP)+,D0        ; D0 := j
        MOVE.L  (SP)+,D1        ; D1 := i

LD      CMP.W   #1,D0	        ; IF j = 1, return i
        BEQ     DV1

        MOVE.L  D1,-(SP)        ; Push i as LONGINT
        MOVE.W  D0,-(SP)        ; Push j as INTEGER

        CLR.L   D1

        TST.W   (SP)	        ; If j is negative, negate both
        BGE     JPOS
        NEG.W   (SP)	        ; negate j
        NEG.L   2(SP)	        ; negate i

JPOS    TST.L   2(SP)	        ; If i is negative, negate it but remember it was
        SMI     D2	        ; D2 := (i < 0)
        BGE     IPOS
        NEG.L   2(SP)	        ; negate i

IPOS    MOVE.W  2(SP),D1        ; Divide MSW of i by j
        DIVU    (SP),D1

        MOVE.L  D1,D0	        ; Remainder becomes MSW of next Divide
        MOVE.W  4(SP),D0        ; Divide ((preceding remainder) concat (LSW of i)) by j
        DIVU    (SP)+,D0        ; Pop j at the same time

        SWAP    D1	        ; Quotient of first divide is MSW of result
        MOVE.W  D0,D1	        ; Quotient of second divide is LSW of result

        TST.B   D2	        ; Was i negative?
        BEQ     DUN
        NEG.L   D1

DUN     ADD.L   #4,SP	        ; Popeye

DV1     MOVE.L  D1,(SP)	        ; Store function result

        JMP     (A0)	        ; Return

        TAIL    'LINTDIVI'

;=============================================================================================

        .FUNC LINTMULI
        HEAD

; FUNCTION  LIntMulInt(i: LONGINT; j: INTEGER): LONGINT;
;
; uses A0,D0,D1,D2
;

        MOVE.L  (SP)+,A0        ; Return address

        MOVE.W  (SP)+,D1        ; D1 := j
        MOVE.L  (SP)+,D0        ; D0 := i

        CMP.W   #1,D1	        ; IF j = 1, return i
        BEQ     MU1

        MOVE.L  D2,-(SP)        ; Save D2

        MOVE.W  D0,D2	        ; D2 := LSW of I
        SWAP    D0	        ; D0 := MSW of I

        MULU    D1,D0	        ; D0 := D0 * j
        LSL.L   #8,D0
        LSL.L   #8,D0
        MULU    D1,D2
        ADD.L   D2,D0	        ; D0 := product

        MOVE.L  (SP)+,D2        ; restore D2

MU1     MOVE.L  D0,(SP)	        ; Store function result

        JMP     (A0)	        ; Return

        TAIL    'LINTMULI'

;=============================================================================================

        .FUNC LINTANDL
        HEAD

; FUNCTION  LIntAndLInt(i, j: LONGINT): LONGINT;
;
; uses A0,D0
;

        MOVE.L  (SP)+,A0        ; Return address

        MOVE.L  (SP)+,D0        ; D0 := j
        AND.L   (SP)+,D0        ; D0 := i AND j

        MOVE.L  D0,(SP)	        ; Store function result

        JMP     (A0)	        ; Return

        TAIL    'LINTANDL'

;=============================================================================================

        .FUNC LINTORLI
        HEAD

; FUNCTION  LIntOrLInt(i, j: LONGINT): LONGINT;
;
; uses A0,D0
;

        MOVE.L  (SP)+,A0        ; Return address

        MOVE.L  (SP)+,D0        ; D0 := j
        OR.L    (SP)+,D0        ; D0 := i OR j

        MOVE.L  D0,(SP)	        ; Store function result

        JMP     (A0)	        ; Return

        TAIL    'LINTORLI'

;=============================================================================================

        .FUNC LINTXORL
        HEAD

; FUNCTION  LIntXorLInt(i, j: LONGINT): LONGINT;
;
; uses A0,D0, D1
;

        MOVE.L  (SP)+,A0        ; Return address

        MOVE.L  (SP)+,D0        ; D0 := j
        MOVE.L  (SP)+,D1        ; D1 := i
        EOR.L   D1,D0	        ; D0 := i XOR j

        MOVE.L  D0,(SP)	        ; Store function result

        JMP     (A0)	        ; Return

        TAIL    'LINTXORL'

;=============================================================================================

        .PROC ENTERLIS
        HEAD

; PROCEDURE EnterLisabug;

        TRAP    #0
        RTS

        TAIL    'ENTERLIS'

;=============================================================================================


        .END



